package com.manager.common.config;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.manager.common.annotation.NestingModel;
import com.manager.common.utils.ClassUtils;
import com.manager.common.utils.ObjectUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

@Component
public class ArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        NestingModel nestingModel = parameter.getParameterAnnotation(NestingModel.class);
        return nestingModel != null;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        Class<?> claz = parameter.getParameterType();
        Object object = claz.newInstance();
        Enumeration<String> enumeration = request.getParameterNames();
        Map<String,String[]> temp = request.getParameterMap();
        while (enumeration.hasMoreElements()) {
            String parameterName = enumeration.nextElement();
            String parameterValue = request.getParameter(parameterName);
            handleObject2(object, parameterName, parameterValue);
        }
        return object;
    }

    private void handleObject2(Object object, String parameterName, String parameterValue) throws Exception{
        Field field = getField(object.getClass(), parameterName);
        if(field == null){
            return;
        }
        Class<?> fieldType = field.getType();
        if(ClassUtils.isSimpleType(fieldType)){
            ClassUtils.setFieldValue(object, parameterValue, parameterName);
            return;
        }
        Object value = null;
        System.out.println(field.getName() + " : " + parameterValue);
        if(fieldType.equals(List.class) ){
            Type genericType = field.getGenericType();
            if (genericType instanceof ParameterizedType) {
                ParameterizedType aType = (ParameterizedType) genericType;
                Type[] fieldArgTypes = aType.getActualTypeArguments();
                if(fieldArgTypes == null || fieldArgTypes.length == 0){
                    return;
                }
                value = ObjectUtils.jsonArray2Bean(parameterValue,Class.forName(fieldArgTypes[0].getTypeName()));
            }
        }else {
            value = ObjectUtils.json2Bean(parameterValue,fieldType);
        }
        field.setAccessible(true);
        field.set(object, value);
    }

    private Field getField(Class<?> claz,String fieldName) {
        Field field = null;
        while (field == null && claz != null) {
            try{
                field = claz.getDeclaredField(fieldName);
            }catch (Exception e){
                claz = claz.getSuperclass();
            }
        }

        return field;
    }

    private void handleObject(Object object, String parameterName, String parameterValue) throws Exception {
        if (!parameterName.contains("[")) {
            ClassUtils.setFieldValue(object, parameterValue, parameterName);
            return;
        }
        String[] parts = parameterName.split("\\[|\\]");
        Object temp = object;
        for (int i = 0; i < parts.length; i++) {
            String part = parts[i];
            if (StringUtils.isEmpty(part)) {
                continue;
            }
            if (i == parts.length - 1 && temp != null) {
                ClassUtils.setFieldValue(temp, parameterValue, part);
                continue;
            }
            temp = ClassUtils.invokeGet(temp, part);
            if (temp != null) {
                continue;
            }
            Field field = null;
            try{
                field = object.getClass().getDeclaredField(part);
            }catch (Exception e){
               try {
                   field = object.getClass().getField(part);
               }catch (Exception ex){
               }
            }
            if (field == null) {
                continue;
            }
            temp = field.getType().newInstance();
            field.setAccessible(true);
            field.set(object, temp);

        }
    }
}
